/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */
#pragma once

#include <vector>
#include "TextureBase.h"
#include "VertexBuffer.h"
#include "PointBuffer.h"
#include <Color.h>
#include <lib3d/Math_lib3d.h>
#include <lib3d/Light.h>
#include <math/Frustrum.h>
#include "BlendMode.h"

namespace liba
{
namespace lib3d
{
namespace hard
{

class RenderLight
{
public:
	RenderLight():
		diffuse(1, 1, 1),
		world_position(0, 0, 0),
		world_direction(0, 1, 0),
		intensity( 1 ),
		is_directional(	false )
	{}

	bool is_directional;
	Color diffuse;
	Color specular;
	Vector world_position;
	Vector world_direction;
	double intensity;
	double range; // calculated from intensity
	Light::AttenuationType attenuation;
	double shadow_priority;
	Vector clq; // calculated from attenuation

	bool operator<(const RenderLight & lwd)const
	{
		return unimportance > lwd.unimportance;
	}
	double unimportance;
};

typedef std::vector<RenderLight> RenderLights;
typedef std::vector<RenderLight *> RenderPLights;

class RenderTexture
{
public:
	RenderTexture()
	:	texture( 0 ),
		alpha_channel( false ),
		wrap( true )
	{}
	TextureBase * texture;
	bool wrap;
	bool alpha_channel;
};

class RenderMaterial
{
public:
	RenderMaterial() : transparency(0.0f), specular_power(0.0f), diffuse(1, 1, 1), emissive(1, 1, 1), specular(1, 1, 1), reflection(1, 1, 1)
	{}
	Color diffuse;
	Color emissive;
	Color specular;
	Color reflection;
//	double reflectivity;
	double specular_power;
	double transparency;

	RenderTexture diffuse_texture;
	RenderTexture emissive_texture;
	
	bool is_transparent()const
	{
		return transparency != 0 || diffuse_texture.alpha_channel || emissive_texture.alpha_channel;
	}
	
#ifndef IPHONE_VERSION
	RenderTexture bump_texture;
	RenderTexture cubic_reflection_texture;
#endif
};

class RenderModel
{
public:
	RenderModel():
		vb( 0 ),
		vb2( 0 ),
		ib( 0 ),
		filter_texture(true),
		blendMode(BM_ALPHA)
	{}
	RenderMaterial material;
	Matrix world;
	Sphere bounding_sphere;

	VertexBuffer * vb;
	VertexBuffer * vb2;
	double morph_weight;

	int primitive_start;
	int primitive_count;

	IndexBuffer * ib;
	int vertex_start;
	int vertex_count;
	bool filter_texture;

	BlendMode blendMode;

	bool operator<(const RenderModel & lwd)const
	{
		return unimportance < lwd.unimportance;
	}
	double unimportance;

#ifndef IPHONE_VERSION
	int last_light_to_use;

	RenderPLights pixel_lights;
	RenderPLights vertex_lights;
#endif
};

/*class RenderModelWater : public RenderModel
{
public:
	RenderModelWater()
	{}
	explicit RenderModelWater(const RenderModel & rm )
		:	RenderModel( rm )
	{}

	Plane plane;
	Vector reflection_position;
	Matrix reflection_scale;
};*/

class RenderSprite
{
public:
	RenderSprite()
		:	vb( 0 )
	{}

	RenderMaterial material;
	Matrix world;
	Matrix emitter;
#ifdef IPHONE_VERSION
	PointBuffer * vb;
#else
	VertexBuffer * vb;
#endif
	int primitive_start;
	int primitive_count;
	double time_elapsed;

	bool operator<(const RenderSprite & lwd)const
	{
		return unimportance < lwd.unimportance;
	}
	double unimportance;
};

typedef std::vector<RenderModel> RenderModels;
//typedef std::vector<RenderModel *> RenderPModels;
//typedef std::vector<RenderModelWater> RenderModelsWater;
typedef std::vector<RenderSprite> RenderSprites;

struct RenderOrderItem
{
	bool is_sprite;
	int number;
	float unimportance;
	
	VertexBuffer * vb;
	TextureBase * tex;
	
	bool operator<(const RenderOrderItem & lwd)const
	{
		if(unimportance != lwd.unimportance)
			return unimportance < lwd.unimportance;
		if(tex != lwd.tex)
			return tex > lwd.tex;

		return vb > lwd.vb;
	}
};
	
typedef std::vector<RenderOrderItem> RenderOrder;
	
class RenderList
{
public:
	RenderList();

	Matrix camera_projection;
	Matrix camera_world;
	Viewport viewport;

	Matrix view_mat; // calculated from camera_world

	Color ambient_color;
	bool clear_render_target;
	math::Frustrum frustrum;
	Color fog_color;
	double fog_range;
	bool perform_viewport_culling;

	RenderLights lights;
	RenderModels models;
	int first_transparent_model; // calculated from models

#ifndef IPHONE_VERSION
	RenderModels shadow_models;
	RenderLights shadow_lights; // calculated from lights
#endif

//	RenderPModels ready_shadow_models;
//	RenderPModels ready_transparent_models;
//	RenderPModels ready_normal_models;
	RenderSprites sprites;

	RenderOrder render_order;

//	void sort_lights();
//	void sort_transparent_models();
	void calculate(int shadow_passes, int lighting_passes);
	// Clears all data from render list and resets it to initial empty state.
	void Clear();
};


} // namespace hard
} // namespace lib3d
} // namespace liba
using namespace liba;
